﻿Imports System.Runtime.InteropServices
Imports System.Reflection

Public Class ListView
	Inherits Windows.Forms.ListView

	Property ImageSize As Drawing.Size
		Get
			Return LargeImageList.ImageSize
		End Get
		Set(ByVal Value As Drawing.Size)
			BeginUpdate()
			OwnerDraw = True
			IconSpacing = New Size(Value.Width * 1.5, Value.Height * 1.5)
			LargeImageList = New ImageList
			LargeImageList.ImageSize = Value
			View = View.LargeIcon
			EndUpdate()
		End Set
	End Property
	Private Declare Function SendMessageW Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr

	Event Activate(ByVal sender As Object, ByVal e As EventArgs)

	Sub New()
		SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint, True)
		DoubleBuffered = True
	End Sub

	Private Sub List_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles Me.ColumnClick
		Sorting = If(Sorting = SortOrder.Ascending, SortOrder.Descending, SortOrder.Ascending)
		ListViewItemSorter = New ListViewColumnSorter(e.Column, Sorting)
		Sort()
	End Sub

	Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
		'MyBase.OnPaint(e)
		Dim R As Rectangle
		For Each Item As ListViewItem In Items
			R = Item.GetBounds(ItemBoundsPortion.Entire)
			If R.IntersectsWith(e.ClipRectangle) Then
				e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.Bilinear
				RaiseEvent PaintItem(Me, e.Graphics, Item, R)
			End If
		Next
	End Sub

	Overloads Sub Sort(ByVal SortColumn As Integer)
		ListViewItemSorter = New ListViewColumnSorter(SortColumn, SortOrder.Ascending)
		Sort()
	End Sub

	Sub SelectAll()
		BeginUpdate()
		For Each Item In Items
			Item.Selected = True
		Next
		EndUpdate()
	End Sub

	Public Function Find(ByVal Text As String) As ListViewItem()
		Return Items.Find(Text, False)
	End Function

	Private Sub List_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DoubleClick
		RaiseEvent Activate(Me, Nothing)
	End Sub

	Event PaintItem(ByVal sender As Object, ByVal G As Graphics, ByVal Item As ListViewItem, ByVal R As Rectangle)
	'Private Sub ListView_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewItemEventArgs) Handles Me.DrawItem
	'	If Updating Then Return
	'	e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.Bilinear
	'	Dim R = e.Item.GetBounds(ItemBoundsPortion.Entire)
	'	RaiseEvent PaintItem(Me, e.Graphics, e.Item, R)
	'End Sub

	Private Sub List_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
		If e.KeyCode = Keys.Enter Then
			e.Handled = True
			RaiseEvent Activate(Me, Nothing)
		End If
	End Sub

	Dim Selection As New List(Of String)
	Sub SaveSelection()
		Selection = (From i As ListViewItem In Items Where i.Selected Select i.Name).ToList
	End Sub
	Sub RestoreSelection()
		SelectedItems.Clear()
		For Each Item In From s In Selection Where Items.ContainsKey(s) Select Items(s)
			Item.Selected = True
		Next
		If SelectedItems.Count > 0 Then SelectedItems(0).EnsureVisible()
	End Sub

	Public Updating As Boolean
	Shadows Sub BeginUpdate()
		If Updating Then Exit Sub
		Updating = True
		MyBase.BeginUpdate()
	End Sub
	Shadows Sub EndUpdate()
		Updating = False
		MyBase.EndUpdate()
	End Sub

	Private Sub ListView_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
		HotItem = Nothing
	End Sub

	Private Sub ListView_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
		HotItem = GetItemAt(e.X, e.Y)
	End Sub

	Dim m_HotItem As ListViewItem
	Property HotItem As ListViewItem
		Get
			Return m_HotItem
		End Get
		Set(ByVal Value As ListViewItem)
			If Value Is HotItem Then Exit Property
			If Not HotItem Is Nothing Then Invalidate(HotItem.Bounds)
			m_HotItem = Value
			If Not HotItem Is Nothing Then Invalidate(HotItem.Bounds)
		End Set
	End Property

	Dim m_DropTarget As ListViewItem
	Property DropTarget As ListViewItem
		Get
			Return m_DropTarget
		End Get
		Set(ByVal Value As ListViewItem)
			If Value Is DropTarget Then Exit Property
			If Not DropTarget Is Nothing Then Invalidate(DropTarget.Bounds)
			m_DropTarget = Value
			If Not DropTarget Is Nothing Then Invalidate(DropTarget.Bounds)
		End Set
	End Property

	Private mSpacing As Size

	Public Property IconSpacing As Size
		Get
			Return mSpacing
		End Get
		Set(ByVal value As Size)
			mSpacing = value
			UpdateSpacing()
		End Set
	End Property

	Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
		MyBase.OnHandleCreated(e)
		UpdateSpacing()
	End Sub

	Private Sub UpdateSpacing()
		'If Me.IsHandleCreated Then SendMessageW(Me.Handle, &H1000 + 53, IntPtr.Zero, mSpacing.Height * 65536 + mSpacing.Width)
	End Sub

	Function Add() As ListViewItem
		Return MyBase.Items.Add("")
	End Function

	Sub Add(ByVal Items() As ListViewItem)
		MyBase.Items.AddRange(Items)
	End Sub

	Sub Remove(ByVal Key As String)
		MyBase.Items.RemoveByKey(Key)
	End Sub

	Sub ClearItems()
		MyBase.Items.Clear()
	End Sub


End Class

Public Class ListViewColumnSorter
	Implements System.Collections.IComparer

	Public SortColumn As Integer = 0
	Public SortOrder As SortOrder = SortOrder.None
	Private Comparer As New CaseInsensitiveComparer

	Sub New(ByVal Column As Integer, ByVal Order As SortOrder)
		SortColumn = Column
		SortOrder = Order
	End Sub

	Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
		Return If(SortOrder = SortOrder.Ascending, 1, -1) * Comparer.Compare(x.SubItems(SortColumn).Text, y.SubItems(SortColumn).Text)
	End Function

End Class

Public Class Panel
	Inherits System.Windows.Forms.Panel

	Sub New()
		DoubleBuffered = True
	End Sub

End Class

